package util.tools.stoich;

import util.core.Equation;
import util.core.Format;
import util.core.Molecule;
import util.core.MoleculeComponent;
import util.exceptions.UnknownElementException;

import java.util.ArrayList;

public class Stoichiometry {


    private Equation eq;
    private ArrayList<Molecule> limiting;
    private double moles;
    private int count;


    public static double getMolarMass(Molecule molecule) {
        ArrayList<MoleculeComponent> elements = molecule.getElements();
        double molarMass = 0;

        for (MoleculeComponent mc : elements) {
            molarMass += mc.getMultiplicity() * mc.getElement().getAtomicWeight();
        }

        return molarMass;
    }

    public static double massToMol(Molecule target, double massOfTarget) {
        double molarMass = getMolarMass(target);
        return massOfTarget / molarMass;
    }

    public static double volumeToMole(double volumeOfTarget) {
        return volumeOfTarget / 22.4;
    }

    public Stoichiometry(Equation eq) {
        this.eq = eq;
        moles = Double.MAX_VALUE;
        limiting = new ArrayList<Molecule>();
    }

    public void add(Molecule target, double quantity, char type) {
        int a = eq.getIndexOf(target);

        if (type == 'l') {
            quantity = volumeToMole(quantity);
        } else if (type == 'g') {
            quantity = massToMol(target, quantity);
        }

        double effectiveMoles = quantity / eq.getBalanceArray()[a];
        if (moles - effectiveMoles > .00000001) {
            moles = effectiveMoles;
            limiting = new ArrayList<Molecule>();
            limiting.add(target);
        } else if (Math.abs(moles - effectiveMoles) < .00000001) {
            limiting.add(target);
        }
        count++;
    }

    public String getResult(Molecule destination, char type) {
        int a = eq.getIndexOf(destination);

        double quantity = moles * eq.getBalanceArray()[a];

        if (type == 'L') {
            quantity = molToVolume(quantity);
        } else if (type == 'g') {
            quantity = molToMass(destination, quantity);
        }

        String unit = "";
        switch (type) {
            case 'g': {
                unit = "gram";
                break;
            }
            case 'L': {
                unit = "liter";
                break;
            }
            case 'm': {
                unit = "mol";
                break;
            }
        }
        if (quantity != 1)
            unit += "s";

        return "<p><b>Result:</b><br/>" + quantity + " " + unit + " of " + Format.toFormattedString(destination) + "</p>";
    }

    public String getLimiting() {
        boolean isFirst = true;
        if (count != limiting.size()) {
            String rep = "";
            for (Molecule c : limiting) {
                if (!isFirst) {
                    rep += " ," + Format.toFormattedString(c);
                } else {
                    rep += Format.toFormattedString(c);
                    isFirst = false;
                }
            }
            return rep;
        }

        return "none";
    }

    public int getLimitingSize() {
        return limiting.size();
    }

    public void add(StoiData c) throws UnknownElementException {
        add(c.getMolecule(), c.getVal(), c.getType());
    }

    public void add(ArrayList<StoiData> m) throws UnknownElementException {
        for (StoiData c : m)
            add(c);
    }


    public static double molToMass(Molecule target, double quantity) {
        double molarMass = getMolarMass(target);
        return quantity * molarMass;
    }

    public static double molToVolume(double quantity) {
        return quantity * 22.4;
    }


}
